package com.test.web;

import com.gargoylesoftware.htmlunit.DefaultCredentialsProvider;
import com.gargoylesoftware.htmlunit.WebClient;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.Select;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * selenium基础类，尽量继承
 */
public abstract class WebsBase {
    private static WebDriver driver;
    private Boolean isProxy=false; //是否使用代理

    public WebDriver getDriver() {
        return driver;
    }

    public void setDriver(WebDriver driver) {
        WebsBase.driver = driver;
    }

    public Boolean getProxy() {
        return isProxy;
    }

    public void setProxy(Boolean proxy) {
        isProxy = proxy;
    }

    /**
     * 设置浏览器驱动
     *
     * @param browser 浏览器枚举
     */
    public void setBrowser(Browsers browser,Proxy proxy){
        if(browser.getKey()!=null||browser.getValue()!=null){
            System.getProperties().setProperty(browser.getKey(),browser.getValue());
            System.setProperty("http.nonProxyHosts", "localhost");
        }
        switch (browser){
            case Chrome:
                if(isProxy&&proxy!=null){
                    DesiredCapabilities cap = new DesiredCapabilities();
                    cap.setCapability(CapabilityType.ForSeleniumServer.AVOIDING_PROXY, true);
                    cap.setCapability(CapabilityType.ForSeleniumServer.ONLY_PROXYING_SELENIUM_TRAFFIC, true);
                    cap.setCapability(CapabilityType.PROXY, proxy);
                    driver=new ChromeDriver(cap);
                }else{
                    driver=new ChromeDriver();
                }
                break;
            case Firefox:
                if(isProxy&&proxy!=null){
                    DesiredCapabilities cap = new DesiredCapabilities();
                    cap.setCapability(CapabilityType.ForSeleniumServer.AVOIDING_PROXY, true);
                    cap.setCapability(CapabilityType.ForSeleniumServer.ONLY_PROXYING_SELENIUM_TRAFFIC, true);
                    cap.setCapability(CapabilityType.PROXY, proxy);
                    driver=new FirefoxDriver(cap);
                }else{
                    driver=new FirefoxDriver();
                }
                break;
            case InternetExplorer:
                if(isProxy&&proxy!=null){
                    DesiredCapabilities ieCapabilities = DesiredCapabilities.internetExplorer();
                    ieCapabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);
                    ieCapabilities.setCapability(CapabilityType.ForSeleniumServer.AVOIDING_PROXY,true);
                    ieCapabilities.setCapability(CapabilityType.ForSeleniumServer.ONLY_PROXYING_SELENIUM_TRAFFIC, true);
                    ieCapabilities.setCapability(CapabilityType.PROXY, proxy);
                    driver=new InternetExplorerDriver(ieCapabilities);
                }else{
                    DesiredCapabilities ieCapabilities = DesiredCapabilities.internetExplorer();
                    ieCapabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);
                    driver=new InternetExplorerDriver(ieCapabilities);
                }
                break;
            case HtmlUnit:
                if(isProxy&&proxy!=null){
                    DesiredCapabilities cap = DesiredCapabilities.htmlUnit();
                    cap.setCapability(CapabilityType.ForSeleniumServer.AVOIDING_PROXY, true);
                    cap.setCapability(CapabilityType.ForSeleniumServer.ONLY_PROXYING_SELENIUM_TRAFFIC, true);
                    cap.setCapability(CapabilityType.PROXY, proxy);
                    driver=new HtmlUnitDriver(cap){
                        @Override
                        protected WebClient modifyWebClient(WebClient client)
                        {
                            DefaultCredentialsProvider creds = new DefaultCredentialsProvider();
                            creds.addCredentials("用户名", "密码");
                            client.setCredentialsProvider(creds);
                            return client;
                        }
                    };
                }else{
                    driver=new HtmlUnitDriver();
                }
                break;
        }
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    }

    public Proxy setProxy(String proxyIpAndPort){
        Proxy proxy = new Proxy();
        proxy.setHttpProxy(proxyIpAndPort).setFtpProxy(proxyIpAndPort).setSslProxy(proxyIpAndPort);
        return proxy;
    }
    /**
     * 打开页面
     *
     * @param url 页面地址
     */
    public void openUrl(String url){
        driver.get(url);
    }

    /**
     * 浏览器工具类
     */
    public static class BrowserUtil{

        /**
         * 最大化
         */
        public static void max(){
            driver.manage().window().maximize();
        }

        /**
         * 刷新当前页面
         */
        public static void refresh(){
            driver.navigate().refresh();
        }

        /**
         * 后退
         */
        public static void back(){
            driver.navigate().back();
        }

        /**
         * 前进
         */
        public static void forward(){
            driver.navigate().forward();
        }

        /**
         * 关闭当前标签
         */
        public static void close(){
            driver.close();
        }

        /**
         * 调整浏览器窗口大小
         *
         * @param x 宽度
         * @param y 高度
         */
        public static void size(int x,int y){
            driver.manage().window().setSize(new Dimension(x,y));
        }

        /**
         * 浏览器全屏
         */
        public static void fullScreen(){
            driver.manage().window().fullscreen();
        }

        /**
         * 获取指定Cookie
         *
         * @param name 获取指定Cookie名称
         * @return Cookie cookie
         */
        public static Cookie getCookie(String name){
            return driver.manage().getCookieNamed(name);

        }

        /**
         * 获取整个Cookie
         *
         * @return Cookie的Set集合 set
         */
        public static Set<Cookie> getCookies(){
            return driver.manage().getCookies();
        }

        /**
         * 增加Cookie，如果存在就不增加，如果同样名称&&同样域&&同样路径则修改value
         *
         * @param name       名称
         * @param value      值
         * @param domain     作用域
         * @param path       路径
         * @param expiry     有效期
         * @param isSecure   是否HTTPS
         * @param isHttpOnly HttpOnly
         */
        public static void addCookie(String name, String value, String domain, String path, Date expiry, boolean isSecure, boolean isHttpOnly){
            Cookie cookie=driver.manage().getCookieNamed(name);
            if(null==cookie){
                driver.manage().addCookie(cookie);
            }else{
                Set<Cookie> cookies=driver.manage().getCookies();
                Cookie ck1=new Cookie(name,value,domain,path,expiry,isSecure,isHttpOnly);
                ck1.validate();
                for (Cookie ck2 : cookies) {
                    if(ck2.getName().equals(ck1.getName())&&ck2.getDomain().equals(ck1.getDomain())&&ck2.getPath().equals(ck1.getPath())){
                        driver.manage().deleteCookie(ck2);
                        driver.manage().addCookie(ck1);

                        return;
                    }
                }
                driver.manage().addCookie(ck1);
            }
        }

        /**
         * 删除cookie
         *
         * @param cookie Cookie对象
         */
        public static void delCookie(Cookie cookie){
            driver.manage().deleteCookie(cookie);
        }

        /**
         * 删除cookie
         *
         * @param name Cookie名称
         */
        public static void delCookie(String name){
            driver.manage().deleteCookieNamed(name);
        }

        /**
         * 删除全部cookie
         */
        public static void delCookies(){
            driver.manage().deleteAllCookies();
        }
    }

    /**
     * 单击
     *
     * @param point 定位
     */
    public void click(By point){
        driver.findElement(point).click();
    }

    /**
     * 输入
     *
     * @param point 定位
     * @param var   输入值
     */
    public void sendKey(By point,String var){
        driver.findElement(point).clear();
        driver.findElement(point).sendKeys(var);
    }

    /**
     * 下拉框
     *
     * @param point 定位
     * @param index 选中目标索引
     */
    public void selectUtil(By point,int index){
        Select select = new Select(driver.findElement(point));//选择对应的选择项： 
//        select.selectByVisibleText("mediaAgencyA");
//        select.selectByValue("MA_ID_001");//不选择对应的选择项： select.deselectAll(); 
//        select.deselectByValue("MA_ID_001");

//        遍历下拉选择
//        for(WebElement e:select.getOptions()){
//            //you logic
//            e.click();
//        }
        select.selectByIndex(index);
    }

    /**
     * 双击
     *
     * @param point 定位
     */
    public void doubleClick(By point){
        Actions action = new Actions(driver);
        action.doubleClick();// 鼠标在当前停留的位置做双击操作
        action.doubleClick(driver.findElement(point));// 鼠标双击指定的元素
    }

    /**
     * 拖拽
     *
     * @param source 源元素
     * @param target 目标元素
     */
    public void drop(WebElement source,WebElement target){
        Actions action = new Actions(driver);// 鼠标拖拽动作，将 source 元素拖放到 target 元素的位置。
        action.dragAndDrop(source,target);// 鼠标拖拽动作，将 source 元素拖放到 (xOffset, yOffset) 位置，其中 xOffset 为横坐标，yOffset 为纵坐标。
    }

    /**
     * 拖拽
     *
     * @param source  源元素
     * @param xOffset 目标x坐标
     * @param yOffset 目标y坐标
     */
    public void drop(WebElement source,int xOffset,int yOffset){
        Actions action = new Actions(driver);// 鼠标拖拽动作，将 source 元素拖放到 target 元素的位置。
        action.dragAndDropBy(source,xOffset,yOffset);
    }

    /**
     * 拖曳
     *
     * @param source 源元素
     * @param target 目标元素
     */
    public void holdDrop(WebElement source,WebElement target){
        Actions action = new Actions(driver);// 鼠标拖拽动作，将 source 元素拖放到 target 元素的位置。
        action.clickAndHold(source).moveToElement(target).perform();
        action.release();
    }

    /**
     * 对元素单击左键不放
     *
     * @param el 元素
     */
    public void hold(WebElement el){
        Actions action = new Actions(driver);
        action.clickAndHold(el);// 鼠标悬停在 el 元素的位置
    }

    /**
     * 鼠标位置单击左键不放
     */
    public void hold(){
        Actions action = new Actions(driver);
        action.clickAndHold();// 鼠标悬停在当前位置，既点击并且不释放
    }

    /**
     * 移动鼠标到元素中心
     *
     * @param el 目标元素
     */
    public void move(WebElement el){
        Actions action = new Actions(driver);
        action.moveToElement(el);// 将鼠标移到 toElement 元素中点
    }

    /**
     * 移动鼠标到元素指定位置
     *
     * @param el      目标元素
     * @param xOffset 以元素 el 的左上角为 (0,0) 开始的 x 坐标
     * @param yOffset 以元素 el 的左上角为 (0,0) 开始的 y 坐标
     */
    public void move(WebElement el,int xOffset,int yOffset){
        Actions action = new Actions(driver);
        // 将鼠标移到元素 toElement 的 (xOffset, yOffset) 位置，
        //这里的 (xOffset, yOffset) 是以元素 el 的左上角为 (0,0) 开始的 (x, y) 坐标轴。
        action.moveToElement(el,xOffset,yOffset);
    }

    /**
     * 移动鼠标到指定位置
     *
     * @param xOffset 以鼠标当前位置或者 (0,0) 为中心开始移动到 x 坐标
     * @param yOffset 以鼠标当前位置或者 (0,0) 为中心开始移动到 y 坐标
     */
    public void move(int xOffset,int yOffset){
        Actions action = new Actions(driver);
        // 以鼠标当前位置或者 (0,0) 为中心开始移动到 (xOffset, yOffset) 坐标轴
        action.moveByOffset(xOffset,yOffset);
    }

    /**
     * hold修饰键
     *
     * @param key 修饰键值（例如：Keys.ALT）
     */
    public void modifierKeyDown(Keys key){
        Actions action = new Actions(driver);
        action.keyDown(key);// 键盘按钮
    }

    /**
     * 释放修饰键
     *
     * @param key 修饰键值（例如：Keys.ALT）
     */
    public void modifierKeyUp(Keys key){
        Actions action = new Actions(driver);
        action.keyUp(key);// 键盘按钮
    }

    /**
     * 新增标签并切换标签
     *
     * @param title 标签标题
     * @param url   新标签地址
     */
    public void addWindowMethod(String title,String url){
        Actions action = new Actions(driver);
        action.sendKeys(Keys.CONTROL + "n").perform();
        switchToWindow(title);
        driver.get(url);
    }

    /**
     * 新增默认标签
     */
    public void addWindowMethod(){
        JavascriptExecutor oJavaScriptExecutor = (JavascriptExecutor)driver;
        oJavaScriptExecutor.executeScript("window.open();");
    }

    /**
     * 新增标签打开链接
     *
     * @param href 链接地址
     */
    public void addWindowMethod(String href){
        JavascriptExecutor oJavaScriptExecutor = (JavascriptExecutor)driver;
        oJavaScriptExecutor.executeScript("window.open('" + href + "')");
    }

    /**
     * 截图，保存在项目的webDriver\Screenshot\下
     */
    public void screenShot()
    {
        File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            FileUtils.copyFile(srcFile, new File("webDriver\\Screenshot\\"+ sdf.format(System.currentTimeMillis())+".jpg"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 切换窗口
     *
     * @param windowTitle 窗口标题
     * @return 状态 boolean
     */
    public boolean switchToWindow(String windowTitle){
        boolean flag = false;
        try {
            //将页面上所有的windowshandle放在入set集合当中
            String currentHandle = driver.getWindowHandle();
            Set<String> handles = driver.getWindowHandles();
            for (String s : handles) {
                if (s.equals(currentHandle))
                    continue;
                else {
                    driver.switchTo().window(s);
                    //和当前的窗口进行比较如果相同就切换到windowhandle
                    //判断title是否和handles当前的窗口相同
                    if (driver.getTitle().contains(windowTitle)) {
                        flag = true;
                        break;
                    } else
                        continue;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
        }
        return flag;
    }

    /**
     * 执行js
     *
     * @param js js代码
     * @return the object
     */
    public Object executeJavaScript(String js){
        return ((JavascriptExecutor) driver).executeScript(js);
    }

    /**
     * 退出
     */
    public void quit(){
        driver.quit();
    }
}
